﻿using System;
using System.Collections.Generic;
using System.Text;
using Mesuro.Common;

namespace Mesuro.Equation {
	public delegate EqConstant EqConstantParser( string expression );
	public abstract class EqConstant : EqTerm {

		private readonly int _tensorRank, _complexRank;

		public int TensorRank {
			get { return _tensorRank; }
		}

		public int ComplexRank {
			get { return _complexRank; }
		}

		public EqConstant( int tensorRank = 0, int complexRank = 0 )
			: base() {
			_tensorRank = tensorRank;
			_complexRank = complexRank;
		}

		public sealed override EqTerm Evaluate( EqScope scope ) {
			return this;
		}


		public abstract override string ToString();

		//-- Static Definition --//
		private static readonly LinkedList<EqConstantParser> ConstantParsers = new LinkedList<EqConstantParser>();

		public static void RegisterParser( EqConstantParser parser ) {
			ConstantParsers.AddLast( parser );
		}
		public static void RemoveParsers( EqConstantParser parser ) {
			while (ConstantParsers.Remove( parser )) ;
		}
		public static EqConstant Parse( string expression ) {
			EqConstant result = null;
			LinkedListNode<EqConstantParser> parser = ConstantParsers.First;
			while (result == null && parser != null) {
				result = parser.Value( expression );
				parser = parser.Next;
			}
			return result;
		}
	}

	class EqRealConstant : EqConstant {
		public static readonly EqOperatorDefinition Addition, Subtraction, Negation, Implicit, Multiplication, Division, Modulo;
		static EqRealConstant() {
			RegisterParser( EqRealConstant.Parser );
			//Addition
			Addition = EqOperatorDefinition.Register( "+", EqOperatorDefinition.PRECEDENCE_ADDITIVE, EqOperatorArguments.BINARY, EqOperatorFlags.Addition, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value + ((EqRealConstant)RHS).Value );
				return null;
			} );
			//Subtraction
			Subtraction = EqOperatorDefinition.Register( "-", EqOperatorDefinition.PRECEDENCE_ADDITIVE, EqOperatorArguments.BINARY, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value - ((EqRealConstant)RHS).Value );
				return null;
			} );
			//Negation
			Negation = EqOperatorDefinition.Register( "-", EqOperatorDefinition.PRECEDENCE_MULTIPLICATIVE, EqOperatorArguments.PREFIX, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (RHS is EqRealConstant)
					return new EqRealConstant( -((EqRealConstant)RHS).Value );
				else
					return new EqOperatorInstance( EqOperatorDefinition.FindOperators( " " ).First.Value ) {
						LHS = new EqRealConstant( -1 ),
						RHS = RHS
					}.Evaluate( scope );
			} );
			//Multiplication
			Multiplication = EqOperatorDefinition.Register( "*", EqOperatorDefinition.PRECEDENCE_MULTIPLICATIVE, EqOperatorArguments.BINARY, EqOperatorFlags.Multiplication, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value * ((EqRealConstant)RHS).Value );
				return null;
			} );
			//Implicit Multiplication
			Implicit = EqOperatorDefinition.Register( " ", EqOperatorDefinition.PRECEDENCE_MULTIPLICATIVE, EqOperatorArguments.BINARY, EqOperatorFlags.Multiplication, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value * ((EqRealConstant)RHS).Value );
				else return new EqOperatorInstance( Multiplication ) { LHS = LHS, RHS = RHS }.Evaluate( scope );
			} );
			//Dvision
			Division = EqOperatorDefinition.Register( "/", EqOperatorDefinition.PRECEDENCE_MULTIPLICATIVE, EqOperatorArguments.BINARY, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value / ((EqRealConstant)RHS).Value );
				return null;
			} );
			//Modulo
			Modulo = EqOperatorDefinition.Register( "mod", EqOperatorDefinition.PRECEDENCE_MULTIPLICATIVE, EqOperatorArguments.BINARY, delegate( EqScope scope, EqTerm LHS, EqTerm RHS, EqOperatorDefinition definition ) {
				if (LHS is EqRealConstant && RHS is EqRealConstant)
					return new EqRealConstant( ((EqRealConstant)LHS).Value % ((EqRealConstant)RHS).Value );
				return null;
			} );
		}
		public static EqRealConstant Parser( string expression ) {
			double d;
			if (Double.TryParse( expression, out d ))
				return new EqRealConstant( d );
			return null;
		}
		private readonly double _value;
		public double Value {
			get { return _value; }
		}

		public EqRealConstant( double value )
			: base( 0, 0 ) {
			_value = value;
		}
		public override int ComplexityCost() {
			return 0;
		}
		public override string ToString() {
			return _value.ToString();
		}
	}
}
